#include "stm32f10x.h"                  // Device header

uint16_t Encoder_Count;

/**
 * @brief 初始化编码器
 *
 * 该函数用于初始化编码器相关的硬件资源，包括时钟、GPIO、AFIO、EXTI和NVIC等。
 * 初始化过程包括以下几个步骤：
 * 1. 配置时钟：使能GPIOB和AFIO的时钟。
 * 2. 配置GPIO：将GPIOB的PIN0和PIN1配置为输入上拉模式，并设置其速率为50MHz。
 * 3. 配置AFIO：配置GPIOB的PIN0和PIN1作为外部中断源。
 * 4. 配置EXTI：配置EXTI0和EXTI1为中断模式，并设置其触发方式为下降沿触发。
 * 5. 配置NVIC：配置NVIC的中断优先级，并启用EXTI0和EXTI1的中断请求。
 *
 * @return 无返回值
 */
void Encoder_Init(void)
{
	//第一步，配置时钟
	//第二步，配置GPIO
	//第三步，配置AFIO
	//第四步，配置EXTI不需要开启时钟
	//第五步，配置NVIC不需要开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed  = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);

	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;//引脚14配置为中断模式
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger= EXTI_Trigger_Falling;//下降沿触发Falling,上升沿触发Rising,上升下降沿触发Rising_Falling.
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//指定通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//指定通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
}

/**
 * @brief 获取编码器当前计数值
 *
 * 此函数用于获取编码器的当前计数值，并清零编码器计数值。
 *
 * @return 返回编码器的当前计数值，类型为int16_t。
 */
int16_t Encoder_Get(void)
{
	int16_t Temp;
	Temp = 10*Encoder_Count;
	Encoder_Count = 0;
	return Temp;
}

/**
 * @brief 外部中断0处理函数
 *
 * 当外部中断线0（EXTI_Line0）触发中断时，该函数被调用。
 *
 * 函数首先检查EXTI_Line0的中断标志位是否被设置。如果设置，则进一步检查GPIOB的GPIO_Pin_1引脚的状态。
 * 如果GPIOB的GPIO_Pin_1引脚为低电平，则将Encoder_Count减一。
 * 最后，清除EXTI_Line0的中断挂起位，以便处理下一次中断。
 */
void EXTI0_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line0 ) == SET)
	{
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)
		{
			Encoder_Count --;
		}
		
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
}

/**
 * @brief EXTI1中断服务例程
 *
 * 该函数是外部中断线1的中断服务例程。当外部中断线1被触发时，该函数将被调用。
 *
 * 函数首先检查EXTI_Line1的中断标志位是否被设置。如果被设置，则进一步检查GPIOB的第0位是否为低电平。
 * 如果是低电平，则将全局变量Encoder_Count加1，表示编码器计数增加。
 * 然后清除EXTI_Line1的中断挂起位，以允许下一次中断的发生。
 */
void EXTI1_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line1 ) == SET)
	{
		if(GPIO_ReadInputDataBit(GPIOB ,GPIO_Pin_0) == 0)
		{
			Encoder_Count ++;
		}
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
}
